import _set from 'lodash/set'
import _isEmpty from 'lodash/isEmpty'

export const changeTreeItem = (tree, func) => {
  const suit = (_tree) => {
    return _tree.map((it) => {
      if (it.children && it.children.length) {
        it.children = suit(it.children)
      }
      it = func(it)
      return it
    })
  }
  return !_isEmpty(tree) ? suit(tree) : []
}

function _basePath (path) {
  if (Array.isArray(path)) return path
  return path.replace(/\[/g, '.').replace(/\]/g, '').split('.')
}

// function _set (object, path, value) {
//   if (typeof object !== 'object') return object
//   _basePath(path).reduce((o, k, i, _) => {
//     if (i === _.length - 1) {
//       o[k] = value
//       return null
//     } else if (k in o) {
//       return o[k]
//     } else {
//       o[k] = /^[0-9]{1,}$/.test(_[i + 1]) ? [] : {}
//       return o[k]
//     }
//   }, object)
//   return object
// }

function changeObjectToParams (val) {
  let obj = {}
  for (const i in val) {
    const it = val[i]
    const key = i
    const arr = key.split('.')

    if (arr.length >= 2) {
      _set(obj, key, it)
    } else {
      obj[key] = it
    }
  }
  return obj
}

export const uuid = () => {
  let temp_url = URL.createObjectURL(new Blob())
  let uuid = temp_url.toString()
  URL.revokeObjectURL(temp_url)
  return uuid.substr(uuid.lastIndexOf('/') + 1)
}

function changeObjToTree (_obj) {
  const func = (obj) => {
    let arr = []
    for (const i in obj) {
      if (Object.prototype.toString.call(obj[i]) === '[object Object]') {
        let children = func(obj[i])
        arr.push({
          parameterKey: i,
          selfType: obj[i]._selfType,
          jsonKey: uuid(),
          selfPath: obj[i].path,
          notEditable: obj[i].notEditable || false,
          ...children.length > 0 ? { children } : {}
        })
      }
    }
    return arr
  }
  return func(_obj)
}

export function analysisJson (json) {
  let obj = {}
  const func = (_json, keyName) => {
    if (Object.prototype.toString.call(_json) === '[object Object]') {
      obj[`${keyName}`] = { _selfType: 'object', path: `${keyName}` }
      for (const i in _json) {
        func(_json[i], `${keyName}.${i}`)
      }
    }

    if (Array.isArray(_json)) {
      obj[keyName] = { _selfType: 'array', path: `${keyName}` }
      const _obj = _json.length > 0 ? _json[0] : null
      if (Object.prototype.toString.call(_obj) === '[object Object]') {
        obj[keyName].ITEMS = { _selfType: 'object', path: '', notEditable: true }
        for (const i in _obj) {
          func(_json[0][i], `${keyName}.ITEMS.${i}`)
        }
      } else {
        obj[keyName].ITEMS = { _selfType: typeof _obj, path: '', notEditable: true }
      }
    }

    if (Object.prototype.toString.call(_json) === '[object Null]') {
      obj[keyName] = { _selfType: 'null', path: `${keyName}` }
    }

    if (['string', 'boolean', 'number'].includes(typeof _json)) {
      obj[keyName] = { _selfType: typeof _json, path: `${keyName}` }
    }
  }

  func(json, 'xx')

  const { xx } = changeObjectToParams(obj)
  return changeObjToTree(xx)
}

export function isJSON (str) {
  if (typeof str == 'string') {
    try {
      JSON.parse(str)
      return true
    } catch (e) {
      return false
    }
  }
}

export function parseSearchArgs (url) {
  let rst = {}
  if (url.indexOf('?') != -1) {
    let str = url.substr(1)
    let parts = str.split('&')
    for (let i = 0; i < parts.length; i++) {
      rst[parts[i].split('=')[0]] = decodeURI(parts[i].split('=')[1])
    }
  }
  return rst
}

export function treeToList (data = [], delChild = true) {
  let resData = []
  for (let obj of data) {
    let child = obj.children
    if (delChild) {
      delete obj.children
    }
    resData.push({ ...obj })
    if (child && child.length > 0) {
      resData = [...resData, ...treeToList(child, delChild)]
    }
  }
  return resData
}

export function delNullChild (_obj) {
  const func = (obj) => {
    return obj.map(it => {
      if (!_isEmpty(it.children)) {
        return {
          ...it,
          returnType: _isEmpty(it.returnType) ? undefined : it.returnType,
          children: func(it.children)
        }
      } else {
        const { children, ...ohter } = it
        return ohter
      }
    })
  }
  return _isEmpty(_obj) ? [] : func(_obj)
}

/* 请求/响应保存前数据处理
 * 1. 过滤掉字段名称为空的数据
 * 2. 补齐新增没有selfPath路径的节点
 */
export const sendBeforeHandle = (list = []) => {
  const process = (_list, parentNode) => {
    _list = _list.filter((node) => {
      return !!node.parameterKey
    })
    for (const node of _list) {
      if (node.parameterKey !== 'ITEMS') {
        node.selfPath = `${parentNode ? parentNode.selfPath : 'xx'}.${node.parameterKey}`
      }
      if (!_isEmpty(node.children)) {
        node.children = process(node.children, node.parameterKey !== 'ITEMS' ? node : parentNode)
      }
    }
    return _list
  }
  // 无需保存根节点信息，从根节点的子集合元素开始处理
  list = list[0]?.isRoot ? (list[0]?.children || []) : list
  list = process(list)
  return list
}

// 请求消息对象数据回显处理成前端需要的数据结构
export const requestReturnShowHandle = (list) => {
  if (!_isEmpty(list)) {
    list = delNullChild(list)
  }
  const process = (_list) => {
    for (const node of _list) {
      node.isCanDelete = true
      if (!_isEmpty(node.children)) {
        process(node.children)
      }
    }
  }
  process(list)
  // 过滤掉值为空的行
  list = list.filter((item) => {
    return item.parameterKey != ''
  })
  list.push({ parameterKey: '', parameterValue: '', parameterName: '', selfType: 'string', jsonKey: uuid() })
  return list
}

// 响应消息对象数组类型特殊处理，数组类型的子元素不可编辑
export const responeArrayHandle = (list = []) => {
  list = delNullChild(list)
  const process = (_list) => {
    for (const node of _list) {
      if (node.parameterKey === 'ITEMS') {
        node.notEditable = true
      }
      if (!node.authPosition) {
        node.authPosition = '1'
      }
      if (!_isEmpty(node.children)) {
        process(node.children)
      }
    }
  }
  process(list)
  // 定义根节点
  const rootType = list.length === 1 && list[0].parameterKey === 'ITEMS' ? 'array' : 'object'
  const rootNode = {
    parameterKey: '根节点',
    parameterValue: '',
    notEditable: true,
    isRoot: true,
    jsonKey: uuid(),
    selfType: rootType
  }
  if (list.length > 0) {
    rootNode.children = list
  }
  return [rootNode]
}

// 将数组形式数据结构转换成json对象数据结构
export const arrayToJSON = (data = [], keyName, isArray) => {
  let jsonObject = {}
  if (isArray) {
    const node = data[0]
    if (node.selfType === 'object') {
      return arrayToJSON(node.children, keyName)
    } else {
      return null
    }
  }
  for (const node of data) {
    if (node.selfType === 'object') {
      jsonObject[node[keyName]] = arrayToJSON(node.children, keyName)
    } else if (node.selfType === 'array') {
      const _array = []
      const result = arrayToJSON(node.children, keyName, true)
      if (result !== null) {
        _array.push(result)
      }
      jsonObject[node[keyName]] = _array
    } else {
      if (node[keyName]) {
        const caseMap = new Map([
          ['string', ''],
          ['number', 1],
          ['boolean', true],
          ['null', null]
        ])
        jsonObject[node[keyName]] = caseMap.get(node.selfType)
      }
    }
  }
  return jsonObject
}

// 根据子元素获取所有上级父元素
export const getParentNodesByChild = (data = [], childNode, key = 'jsonKey') => {
  const parentNodes = []
  function recursionFind (data) {
    let isFind = false
    isFind = data.some((node) => {
      return node[key] === childNode[key]
    })
    if (!isFind) {
      for (const node of data) {
        if (node.children) {
          parentNodes.push(node)
          if (recursionFind(node.children)) {
            isFind = true
            break
          } else {
            parentNodes.pop()
          }
        }
      }
    }
    return isFind
  }
  recursionFind(data)
  return parentNodes
}

// 构造前端树形所需数据结构
export const makeTreeDataStructure = (data = []) => {
  for (const node of data) {
    node.nodeType = getTypeByNode(node)
    node.label = node.name
    node.scopedSlots = {
      title: 'action'
    }
    if (node.children) {
      makeTreeDataStructure(node.children)
    }
  }
}

let dragElementKeys = [] // 可放置区域的行key集合 dragElementKeys，字段表格行只能在同层级拖放，不能跨级
export const onDragEventListener = (target, type, list = [], callback = null) => {
  let childs = [], targetEle = null
  // 递归获取到指定父元素
  const getTrNode = (_target = null) => {
    let trNode = _target
    while (trNode && !trNode.getAttribute('data-row-key')) {
      trNode = trNode.parentNode
    }
    return trNode
  }
  const sourceNode = getTrNode(target)
  const sourceKey = sourceNode.getAttribute('data-row-key')
  // 拖拽过程中触发事件
  const onDragHandle = (event) => {
    event.preventDefault()
    targetEle = event.target
  }
  // 拖放事件结束触发
  const onDragEnd = () => {
    targetEle = getTrNode(targetEle)
    const targetKey = targetEle ? targetEle.getAttribute('data-row-key') : ''
    if (targetKey && targetKey !== sourceKey) {
      const sourceIndex = childs.findIndex((item) => item.jsonKey === sourceKey)
      const targetIndex = childs.findIndex((item) => item.jsonKey === targetKey)
      const source = childs[sourceIndex]
      childs.splice(sourceIndex, 1)
      childs.splice(targetIndex, 0, source)
    }
    removeEventListener()
    if (typeof callback === 'function') {
      callback()
    }
  }
  // 拖放过程中进入目标元素添加样式
  const onAddClassHandle = (event) => {
    const _target = getTrNode(event.target)
    if (_target.classList.contains('ant-table-row')) {
      _target.classList.add('dragging')
    }
  }
  // 拖放过程中离开目标元素删除样式
  const onRemoveClassHandle = (event) => {
    const _target = getTrNode(event.target)
    if (event.target.classList.contains('ant-table-row-cell-break-word')) {
      _target.classList.remove('dragging')
    }
  }
  // 删除拖放事件监听
  const removeEventListener = () => {
    sourceNode.setAttribute('draggable', false)
    for (const key of dragElementKeys) {
      const dragEle = sourceNode.parentNode.querySelector("[data-row-key='" + key + "']")
      dragEle.removeEventListener('drop', onDragHandle)
      dragEle.removeEventListener('dragenter', onAddClassHandle)
      dragEle.removeEventListener('dragleave', onRemoveClassHandle)
      dragEle.classList.remove('dragging')
    }
    sourceNode.removeEventListener('dragend', onDragEnd)
  }
  // 添加拖放事件监听
  const onEventListener = (trNode) => {
    for (const key of dragElementKeys) {
      const dragEle = trNode.parentNode.querySelector(`tr[data-row-key='${key}']`)
      dragEle.addEventListener('drop', onDragHandle)
      if (key !== sourceKey) {
        dragEle.addEventListener('dragenter', onAddClassHandle)
        dragEle.addEventListener('dragleave', onRemoveClassHandle)
        dragEle.addEventListener('dragover', (event) => {
          // 阻止默认行为以允许放置
          event.preventDefault()
        })
      }
    }
  }
  if (type === 'remove') {
    removeEventListener()
    return false
  }
  // 获取当前拖放元素的父元素，便于后面得到可放置的同层子元素
  const parentNodes = getParentNodesByChild(list, { jsonKey: sourceKey })
  if (parentNodes.length > 0) {
    const parentNode = parentNodes.pop()
    childs = parentNode.children
  } else {
    childs = list
  }
  dragElementKeys = childs.map(item => item.jsonKey)
  if (type === 'listener') {
    onEventListener(sourceNode)
    sourceNode.setAttribute('draggable', true) // 开启可拖拽
    sourceNode.addEventListener('dragstart', (event) => {
      event.dataTransfer.effectAllowed = 'move'
    })
    sourceNode.addEventListener('dragend', onDragEnd)
  }
}

/**
 * 设置前端节点类型nodeType定义，可选值为
 * GROUP、CONNECTOR、GET、POST、RABBITMQ、KAFKA、ROCKETMQ
 * */
function getTypeByNode (node) {
  // 初始化加载树，如果节点type字段值为0，表示为分组节点，其他为连接器节点
  return node.type === '0' ? 'GROUP' : 'CONNECTOR'
}
